package easy.trace.plugin.springmvc;


import easy.trace.core.Carrier;
import easy.trace.core.ICarrier;
import easy.trace.core.Interceptor;
import easy.trace.core.context.TraceContext;
import easy.trace.core.dto.ExceptionType;
import easy.trace.core.dto.TransferParams;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author easy
 */
public class SpringMvcInterceptor extends HandlerInterceptorAdapter implements Interceptor {
    private ICarrier currentCarrier;
    private AtomicBoolean isStartCarrier = new AtomicBoolean(false);
    private static final int MAX_ERROR_STATUS_CODE = 400;
    private ConcurrentHashMap<String, ICarrier> carrierHashMap = new ConcurrentHashMap<>();
    private static final String SPRING_CARRIER = "carrier";
    private static final String HOMEPAGE_CARRIER = "homePageCarrier";

    public SpringMvcInterceptor() {
        if (!isStartCarrier.get()) {
            System.out.println("------SpringMVCInterceptor start-----");
            try {
                this.carrierHashMap.put(SPRING_CARRIER, new Carrier());
                this.carrierHashMap.put(HOMEPAGE_CARRIER, new HomePageCarrier());
                isStartCarrier.set(true);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("------SpringMVCInterceptor error-----");
            }
            System.out.println("------SpringMVCInterceptor end-----");
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpRequestContext context = new HttpRequestContext(request);
        setCurrentCarrier(context);
        init(context);
        beforeHandle();
        return true;
    }

    private void setCurrentCarrier(HttpRequestContext context) {
        TransferParams transferParams = context.getTransferParams();
        if (transferParams.notExistTraceHeader()) {
            this.currentCarrier = this.carrierHashMap.get(HOMEPAGE_CARRIER);
        } else {
            this.currentCarrier = this.carrierHashMap.get(SPRING_CARRIER);
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (Objects.nonNull(ex)) {
            encounterException(ex);
        }
        if (response != null && Objects.isNull(ex)) {
            int statusCode = response.getStatus();
            if (statusCode >= MAX_ERROR_STATUS_CODE) {
                encounterException(new TimeoutException("状态码:" + statusCode));
            }
        }
        afterHandle();
    }

    @Override
    public void init(TraceContext context) {
        Optional.ofNullable(currentCarrier).ifPresent((car) -> car.init(context));
    }

    @Override
    public void beforeHandle() {
        Optional.ofNullable(currentCarrier).ifPresent((car) -> car.doBeforeHandle());
    }

    @Override
    public void afterHandle() {
        Optional.ofNullable(currentCarrier).ifPresent((car) -> car.doAfterHandle());
    }

    @Override
    public void encounterException(Exception e) {
        Optional.ofNullable(currentCarrier).ifPresent((car) -> car.doEncounterException(e, ExceptionType.HTTP));
    }
}
